package com.lianqi.emcpframework.core.exception;


import com.lianqi.emcpframework.core.exception.international.InternationalAble;
import com.lianqi.emcpframework.core.exception.international.LocaleMessageProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

/**
 * @program emcp-framework
 * @ClassName EmcpException
 * @description: 平台异常定义类
 * @author: sky
 * @create: 2018/11/14 13:14
 */
public class EmcpException extends RuntimeException implements InternationalAble {

    protected static final Logger LOGGER = LoggerFactory.getLogger(EmcpException.class);

    private final Map<String, Object> parameters = new HashMap<>();

    private static final String ERROR_FORMAT = "{\"error\":\"%s\",\"error_append\":\"%s\",\"error_code\":%s,\"request\":\"%s\"}";
    private ExcepFactor factor;
    private String errorMsgDef;
    private LocaleMessageProvider messageProvider;

    public void setMessageProvider(LocaleMessageProvider messageProvider) {
        this.messageProvider = messageProvider;
    }

    protected EmcpException(ExcepFactor factor) {
        this(factor, factor.getErrorMsg(), null);
    }

    protected EmcpException(Exception e) {
        this(ExcepFactor.E_DEFAULT, e.getMessage());
    }

    protected EmcpException(String message) {
        this(ExcepFactor.E_DEFAULT, message);
    }

    public EmcpException(ExcepFactor factor, Object message) {
        this(factor, message, null);
    }

    protected EmcpException(ExcepFactor factor, Object message, String errorMsgDef) {
        super(message == null ? factor.getErrorMsg() : message.toString());
        this.factor = factor;
        this.errorMsgDef = errorMsgDef;
    }

    protected EmcpException(ExcepFactor factor, Throwable throwable) {
        this(factor, throwable, null);
    }

    protected EmcpException(ExcepFactor factor, Throwable throwable, String errorMsgDef) {
        super(throwable);
        this.factor = factor;
        this.errorMsgDef = errorMsgDef;
    }

    protected EmcpException(ExcepFactor factor, Object[] args) {
        this(factor, factor.getErrorMsg(args), null);
    }

    protected EmcpException(ExcepFactor factor, Object[] errorArgs, Object errorCnArgs) {
        this(factor, factor.getErrorMsg(errorArgs), null);
    }


    public void setTraceHeader(String name, Object value) {
        parameters.put(name, value);
    }

    public Map<String, Object> getTraceHeaders() {
        return parameters;
    }

    public String getErrorMsgDef() {
        return errorMsgDef;
    }

    public ExcepFactor getFactor() {
        return factor;
    }

    protected void setFactor(ExcepFactor factor) {
        this.factor = factor;
    }

    public String formatException(String path) {
        if (path == null) {
            throw new IllegalArgumentException("parameter path is null");
        }
        return String.format(ERROR_FORMAT, this.getMessage(), this.getErrorMsgDef(),
                this.getFactor().getErrorCode(), path);
    }

    public void formatException(String path, Writer writer) {
        String formatMsg = this.formatException(path);
        try {
            writer.write(formatMsg);
        } catch (IOException e) {
            LOGGER.error("formatException", e);
        }
    }


    @Override
    public String localeMessage(Object... args) {
        String localeMsg = this.getErrorMsgDef();
        try {
            localeMsg = messageProvider.getMessage(
                    StringUtils.isEmpty(localeMsg) == true ?
                            String.valueOf(this.getFactor().getErrorCode()) : localeMsg, args);
        } catch (Exception e) {
            LOGGER.error("parser to locale Message error:" + e.getMessage());
        }
        if (StringUtils.isEmpty(localeMsg)) {
            localeMsg = this.getFactor().getErrorMsg(args);
        }
        return localeMsg;
    }
}
